﻿Imports XL.Common
Imports XL.Common.Utils
Imports XL.Win
Imports XL.Win.Utils
Imports System.Globalization
Imports System.Threading
Imports System.Diagnostics
Imports System.Text

Namespace Utils

    Public Class SMSSender
        Implements XL.Common.Interfaces.ISMSMessager

        Public Function SendMessage(ByVal phoneNo As String, ByVal message As String) As Boolean Implements XL.Common.Interfaces.ISMSMessager.SendMessage
            Dim length As String = String.Empty
            Dim smsContent = Me.smsDecodedsms(String.Empty, phoneNo, message, length)
            Console.WriteLine(smsContent)

            Dim port As New System.IO.Ports.SerialPort("COM1")
            AddHandler port.DataReceived, AddressOf Me.PortDataReceived
            port.Handshake = IO.Ports.Handshake.RequestToSend
            port.PortName = "COM1"
            port.BaudRate = 19200
            port.DataBits = 8
            port.StopBits = IO.Ports.StopBits.One
            port.Parity = IO.Ports.Parity.None
            port.Handshake = IO.Ports.Handshake.XOnXOff

            port.Open()
            port.Write(String.Format("AT" & vbCr))
            System.Threading.Thread.Sleep(100)
            port.Write(String.Format("AT+CSQ" & vbCr))
            System.Threading.Thread.Sleep(100)
            port.Write(String.Format("AT+CNMI=1,1" & vbCr))
            System.Threading.Thread.Sleep(100)
            port.Write(String.Format("AT+CMGF=0" & vbCr))
            System.Threading.Thread.Sleep(100)
            port.Write(String.Format("AT+CGSN" & vbCr))
            System.Threading.Thread.Sleep(100)
            port.Write(String.Format("AT" & vbCr))
            System.Threading.Thread.Sleep(100)
            port.Write(String.Format("AT+CMGS={0}" & vbCr, length))
            System.Threading.Thread.Sleep(100)
            port.Write(String.Format("{0}", smsContent))
            System.Threading.Thread.Sleep(1000)
            port.Write(New Char() {Chr(26)}, 0, 1)

            port.Close()

            WinTK.OutputLog("Send SMS", String.Format("phoneNo: {0} at {1:HH:mm:ss}", message, CommTK.GetSyncServerTime))
        End Function

        Private Sub PortDataReceived(ByVal sender As Object, ByVal e As EventArgs)
            Dim port = DirectCast(sender, IO.Ports.SerialPort)
            WinTK.OutputLog("Port data received:", port.ReadExisting())
        End Sub


        '要发送内容的长度,由两部分组成,接收手机号加上要发送的内容
        ''' <summary>
        ''' 函数功能：短信内容编码
        ''' 函数名称：smsPDUEncoded(string srvContent)
        ''' 参 数：srvContent 要进行转换的短信内容,string类型
        ''' 返 回 值：编码后的短信内容，string类型
        ''' 程 序 员：sillnet@163.net
        ''' 编制日期：2003-10-15
        ''' 函数说明：
        ''' 1，采用Big-Endian 字节顺序的 Unicode 格式编码，也就说把高低位的互换在这里完成了
        ''' 2，将转换后的短信内容存进字节数组
        ''' 3，去掉在进行Unicode格式编码中，两个字节中的"-",例如：00-21，变成0021
        ''' 4，将整条短信内容的长度除2，保留两位16进制数
        ''' </summary>
        Public Function smsPDUEncoded(ByVal srvContent As String) As String
            Dim encodingUTF As Encoding = System.Text.Encoding.BigEndianUnicode
            Dim s As String = Nothing
            Dim encodedBytes As Byte() = encodingUTF.GetBytes(srvContent)
            For i As Integer = 0 To encodedBytes.Length - 1
                s += BitConverter.ToString(encodedBytes, i, 1)
            Next
            s = String.Format("{0:X2}{1}", CommTK.FInteger(s.Length / 2), s)

            Return s
        End Function

        ''' <summary>
        ''' 函数功能：短信中心号编码
        ''' 函数名称：smsDecodedCenterNumber(string srvCenterNumber)
        ''' 参 数：srvCenterNumber 要进行转换的短信中心号,string类型
        ''' 返 回 值：编码后的短信中心号，string类型
        ''' 程 序 员：sillnet@163.net
        ''' 编制日期：2003-10-15
        ''' 函数说明：
        ''' 1，将奇数位和偶数位交换。
        ''' 2，短信中心号奇偶数交换后，看看长度是否为偶数，如果不是，最后添加F
        ''' 3，加上短信中心号类型，91为国际化
        ''' 4，计算编码后的短信中心号长度，并格化成二位的十六进制
        ''' </summary>
        Public Function smsDecodedCenterNumber(ByVal srvCenterNumber As String) As String
            Dim s As String = Nothing
            Dim nLength As Integer = srvCenterNumber.Length
            For i As Integer = 1 To nLength - 1 Step 2
                '奇偶互换
                s += srvCenterNumber(i)
                s += srvCenterNumber(i - 1)
            Next
            If Not (nLength Mod 2 = 0) Then
                '是否为偶数，不是就加上F，并对最后一位与加上的F位互换
                s += "F"c
                s += srvCenterNumber(nLength - 1)
            End If
            s = [String].Format("91{0}", s)
            '加上91,代表短信中心类型为国际化
            s = [String].Format("{0:00}{1}", s.Length / 2, s)
            '编码后短信中心号长度，并格式化成二位十六制
            Return s
        End Function

        ''' <summary>
        ''' 函数功能：接收短信手机号编码
        ''' 函数名称：smsDecodedNumber(string srvNumber)
        ''' 参 数：srvCenterNumber 要进行转换的短信中心号,string类型
        ''' 返 回 值：编码后的接收短信手机号，string类型
        ''' 程 序 员：sillnet@163.net
        ''' 编制日期：2003-10-15
        ''' 函数说明：
        ''' 1，检查当前接收手机号是否按标准格式书写，不是，就补上“86”
        ''' 1，将奇数位和偶数位交换。
        ''' 2，短信中心号奇偶数交换后，看看长度是否为偶数，如果不是，最后添加F
        ''' </summary>
        Public Function smsDecodedNumber(ByVal srvNumber As String) As String
            Dim s As String = Nothing
            'if (!(srvNumber.Substring(0, 2) == "86"))
            '{
            ' srvNumber = String.Format("86{0}", srvNumber); //检查当前接收手机号是否按标准格式书写，不是，就补上“86”
            '}
            Dim nLength As Integer = srvNumber.Length
            For i As Integer = 1 To nLength - 1 Step 2
                '将奇数位和偶数位交换
                s += srvNumber(i)
                s += srvNumber(i - 1)
            Next
            If Not (nLength Mod 2 = 0) Then
                '是否为偶数，不是就加上F，并对最后一位与加上的F位互换
                s += "F"c
                s += srvNumber(nLength - 1)
            End If
            Return s
        End Function

        ''' <summary>
        ''' 函数功能：整个短信的编码
        ''' 函数名称：smsDecodedsms(string strCenterNumber, string strNumber, string strSMScontent)
        ''' 参 数：strCenterNumber 要进行转换的短信中心号,string类型
        ''' strNumber 接收手机号码，string类型
        ''' strSMScontent 短信内容
        ''' 返 回 值：完整的短信编码，可以在AT指令中执行，string类型
        ''' 程 序 员：sillnet@163.net
        ''' 编制日期：2003-10-15
        ''' 函数说明：
        ''' 11000D91和000800 在国内，根据PDU编码原则，我们写死在此，详细解释请看我的文章
        ''' </summary>
        Public Function smsDecodedsms(ByVal strCenterNumber As String, ByVal strNumber As String, ByVal strSMScontent As String, ByRef length As String) As String
            Dim s As String = [String].Format("0011000Ba1{1}0008AA{2}", smsDecodedCenterNumber(strCenterNumber), smsDecodedNumber(strNumber), smsPDUEncoded(strSMScontent))
            length = String.Format("{0:D2}", CommTK.FInteger((s.Length - 2) / 2))

            '获取短信内容加上手机号码长度
            'string s = String.Format("{0}11000D91{1}000800{2}", smsDecodedCenterNumber(strCenterNumber), smsDecodedNumber(strNumber), smsPDUEncoded(strSMScontent));
            'nLength = String.Format("{0:D2}", (s.Length - smsDecodedCenterNumber(strCenterNumber).Length) / 2); //获取短信内容加上手机号码长度
            Return s
        End Function


    End Class

End Namespace
